#include <csugl.h>

#include "imgui.h"

struct PTCamera
{
    PTCamera(const glm::vec3 &origin, float fov, float near, float far)
        : origin(origin), fov(fov), near(near), far(far), yaw(90.0f), pitch(0.0f)
    {
        m_front = glm::normalize(glm::vec3{glm::cos(glm::radians(yaw)) * glm::cos(glm::radians(pitch)),
                                                    glm::sin(glm::radians(pitch)),
                                                    -glm::sin(glm::radians(yaw)) * glm::cos(glm::radians(pitch))});
    }

    void update()
    {
        is_update = false;
        if (ImGui::IsWindowFocused())
        {
            if (ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
                is_update = true;
                auto delta = ImGui::GetMouseDragDelta();
                yaw -= (ImGui::GetMousePos().x - last_cursor_pos.x) * moveSpeed * 1.8f;
                pitch = glm::clamp(pitch - (ImGui::GetMousePos().y - last_cursor_pos.y) * moveSpeed * 1.8f,
                                   -89.9f, 89.9f);
                m_front = glm::normalize(glm::vec3{glm::cos(glm::radians(yaw)) * glm::cos(glm::radians(pitch)),
                                                            glm::sin(glm::radians(pitch)),
                                                            -glm::sin(glm::radians(yaw)) * glm::cos(glm::radians(pitch))});
            }
            if (csugl::Input::IsKeyPressed(csugl::Key::W)) { // Front
                is_update = true;
                origin += m_front * moveSpeed;
            }
            if (csugl::Input::IsKeyPressed(csugl::Key::S)) { // Back
                is_update = true;
                origin -= m_front * moveSpeed;
            }
            if (csugl::Input::IsKeyPressed(csugl::Key::A)) { // Left
                is_update = true;
                origin -= get_right() * moveSpeed;
            }
            if (csugl::Input::IsKeyPressed(csugl::Key::D)) { // Right
                is_update = true;
                origin += get_right() * moveSpeed;
            }
            last_cursor_pos = {ImGui::GetMousePos().x, ImGui::GetMousePos().y};
        }
    }

    glm::vec3 get_right() const {
        return glm::normalize(glm::cross(m_front, {0, 1.0f, 0}));
    }

    glm::vec3 get_up() const {
        return glm::normalize(glm::cross(get_right(), m_front));
    }

    void GetLBHV(glm::vec3& leftBottom, glm::vec3& hor, glm::vec3& ver) const {
        float theta = fov;
        float height = 2.0f * tan(theta * 0.5f);
        float width = height * aspect;
        auto right  = get_right();
        auto up = get_up();
        leftBottom = origin + m_front - width / 2 * right - height / 2 * up;
        hor = width * right;
        ver = height * up;
    }

    inline void set_aspect(float as)
    {
        if (as != aspect)
            is_update = true;
        aspect = as;
    }

    inline bool is_updated() { return is_update; }

    float aspect, fov, near, far;
    float moveSpeed = 0.1f;
    glm::vec3 origin;

private:
    float yaw, pitch;
    glm::vec3 m_front;
    // glm::quat rotation;
    glm::vec2 last_cursor_pos;
    bool is_update=false;
};